package com.mediatecture.flex.component.UValueCalculator
{
	import Model.ConstructionLang;
	import Model.Layer;
	import Model.Material;
	
	import mx.collections.ArrayCollection;
	
	public class UValueCalculator
	{
		public static function calculateUValue(construction:ConstructionLang):Number
		{
			if(constructionIsHomogen(construction))
			{
				return calculateHomogenConstructionUvalue(construction);
			}
			else
			{
				return calculateNotHomogenConstructionUvalue(construction);
			}
		}
		
		private static function calculateHomogenConstructionUvalue(construction:ConstructionLang):Number
		{
			var result:Number = 0;
			
			var homogen:Number = calculateHomogenLayers(construction.layers) + 0.13 + 0.13;
			
			return 1/homogen;
		}
		
		private static function calculateNotHomogenConstructionUvalue(construction:ConstructionLang):Number
		{
			var result:Number = 0;
			
			var RUpperT:Number = calculateRUpperT(construction);
			var RLowerT:Number =  calculateRLowerT(construction);
			
			result = 1/((RUpperT + RLowerT)/2);
			
			return result;
		}
		
		private static function testCase(numberOfCases:Number, construction:ConstructionLang, homogenLayersResult:Number):Number
		{
			var result:Number = 0;
			var allHeterogenLayers:ArrayCollection = getAllHeterogenLayers(construction);
			var F:Number = 0;
			var R:Number = 0;
			
			switch(numberOfCases)
			{
				case 8:
					
					for(var i:Number = 0; i <= 1 ; i++)
					{
						for(var j:Number = 0; j <= 1 ; j++)
						{
							for(var k:Number = 0; k <= 1 ; k++)
							{
								F = (((((allHeterogenLayers[0] as Layer).materials[i] as Material).width/100)/
									(((allHeterogenLayers[0] as Layer).materials[0] as Material).width/100 + ((allHeterogenLayers[0] as Layer).materials[1] as Material).width/100)) *
									
									((((allHeterogenLayers[1] as Layer).materials[j] as Material).width/100)/
										(((allHeterogenLayers[1] as Layer).materials[0] as Material).width/100 + ((allHeterogenLayers[1] as Layer).materials[1] as Material).width/100)) *
									
									((((allHeterogenLayers[2] as Layer).materials[k] as Material).width/100)/
										(((allHeterogenLayers[2] as Layer).materials[0] as Material).width/100 + ((allHeterogenLayers[2] as Layer).materials[1] as Material).width/100)));
								
								
								R = (((allHeterogenLayers[0] as Layer).selectedDimention/100)/((allHeterogenLayers[0] as Layer).materials[i] as Material).lambda +
									
									
									((allHeterogenLayers[1] as Layer).selectedDimention/100)/((allHeterogenLayers[1] as Layer).materials[j] as Material).lambda +
									
									
									((allHeterogenLayers[2] as Layer).selectedDimention/100)/((allHeterogenLayers[2] as Layer).materials[k] as Material).lambda +
									
									homogenLayersResult + 2* 0.13);
								
								result += F/R;
							}
						}
					}
					
					break;
				
				case 4:
					
					
					for(var i:Number = 0; i <= 1 ; i++)
					{
						for(var j:Number = 0; j <= 1 ; j++)
						{
							F = (((((allHeterogenLayers[0] as Layer).materials[i] as Material).width/100)/
								(((allHeterogenLayers[0] as Layer).materials[0] as Material).width/100 + ((allHeterogenLayers[0] as Layer).materials[1] as Material).width/100)) *
								
								((((allHeterogenLayers[1] as Layer).materials[j] as Material).width/100)/
									(((allHeterogenLayers[1] as Layer).materials[0] as Material).width/100 + ((allHeterogenLayers[1] as Layer).materials[1] as Material).width/100)));
							
							R = (((allHeterogenLayers[0] as Layer).selectedDimention/100)/((allHeterogenLayers[0] as Layer).materials[i] as Material).lambda +
								
								((allHeterogenLayers[1] as Layer).selectedDimention/100)/((allHeterogenLayers[1] as Layer).materials[j] as Material).lambda +
								
								homogenLayersResult + 2* 0.13);
							
							result += F/R;
						}
					}
					
					break;
				
				case 2:
					
					
					for(var i:Number = 0; i <= 1 ; i++)
					{
						for(var j:Number = 0; j <= 1 ; j++)
						{
							F = ((((allHeterogenLayers[0] as Layer).materials[i] as Material).width/100)/
								(((allHeterogenLayers[0] as Layer).materials[0] as Material).width/100 + ((allHeterogenLayers[0] as Layer).materials[1] as Material).width/100));
							
							R = (((allHeterogenLayers[0] as Layer).selectedDimention/100)/((allHeterogenLayers[0] as Layer).materials[i] as Material).lambda +
								
								homogenLayersResult + 2* 0.13);
							
							result += F/R;
						}
					}
					
					break;
			}
			
			return result
		}
		
		private static function calculateRUpperT(construction:ConstructionLang):Number
		{
			var result:Number = 0;
			
			var homogenLayersResult:Number = calculateHomogenLayers(construction.layers);
			var totalWidth:Number = getTotalWidthOfTheMaterialsInNonHomogenLayers(construction);
			var allMaterialTypes:ArrayCollection = getAllTypesOfMaterialsInNonHomogenLayers(construction);
			
			var numberOfCases:Number = Math.pow(allMaterialTypes.length,getNumberOfHeterogenLayers(construction));
			
			testCase(numberOfCases,construction,homogenLayersResult);
			
			/*	for(var i:Number = 0; i < numberOfCases; i++)
			{ 
			var materialRatio:Number = (getTotalWidthOfMaterialInNothomogenLayers(allMaterialTypes[i], construction.layers)/totalWidth);
			var Rmaterial:Number = (calculateNotHomogenLayerPerMaterial(allMaterialTypes[i], construction.layers) + homogenLayersResult + (2*0.13));
			result += materialRatio / Rmaterial;
			}*/
			
			return 1/testCase(numberOfCases,construction,homogenLayersResult);
		}
		
		private static function calculateRLowerT(construction:ConstructionLang):Number
		{
			var result:Number = 0;
			var first:Number = 0;
			var second:Number = 0;	
			var f1:Number = 0;
			var f2:Number = 0;
			var width11:Number = 0;
			var width12:Number = 0;
			var width21:Number = 0;
			var width22:Number = 0;
			
			for each(var heterogenLayer:Layer in getAllHeterogenLayers(construction))
			{
				width11 = (heterogenLayer.materials[1] as Material).width;
				width12 = (heterogenLayer.materials[0] as Material).width;
				
				if(width11 < width12)
				{
					f1 = ( (width11/100) / (width12/100));
					f2 = (1 - ((width11/100) / (width12/100)) );
					
					first =  f1 /
						((heterogenLayer.selectedDimention/100)/(heterogenLayer.materials[1] as Material).lambda);
					
					second = f2 / 
						((heterogenLayer.selectedDimention/100)/(heterogenLayer.materials[0] as Material).lambda);
					
					result += 1/ (first + second);
				}
					
				else
				{
					f1 = ( (width12/100) / (width11/100));
					f2 = (1 - ((width12/100) / (width11/100)) );
					
					first =  f1 /
						((heterogenLayer.selectedDimention/100)/(heterogenLayer.materials[0] as Material).lambda);
					
					second = f2 / 
						((heterogenLayer.selectedDimention/100)/(heterogenLayer.materials[1] as Material).lambda);
					
					result += 1/ (first + second);
				}
			}
			
			result += calculateHomogenLayers(construction.layers) + (2*0.13);
			
			return result;
		}
		
		private static function getTotalWidthOfTheMaterialsInNonHomogenLayers(construction:ConstructionLang):Number
		{
			var result:Number = 0;
			
			for each(var layer:Layer in construction.layers)
			{
				if(!layer.homogen)
				{
					for each(var material:Material in layer.materials)
					{
						result+= material.width/100;
					}
				}
			}
			
			return result;
		}
		
		private static function getAllTypesOfMaterialsInNonHomogenLayers(construction:ConstructionLang):ArrayCollection
		{
			var result:ArrayCollection = new ArrayCollection();
			
			for each(var layer:Layer in construction.layers)
			{
				if(!layer.homogen)
				{
					for each(var material:Material in layer.materials)
					{
						if(!result.contains(material.type))
						{	
							result.addItem(material.type);
						}
					}
				}
			}
			
			return result;
		}
		
		
		private static function calculateNotHomogenLayerPerMaterial(typeOfMaterial:Number, layers:ArrayCollection):Number
		{
			var result:Number = 0;
			
			for each( var layer:Layer in layers )
			{
				if(!layer.homogen && layerContainsTypeOfMaterial(typeOfMaterial,layer))
				{
					
					result += (layer.selectedDimention/100) / getMaterialByType(typeOfMaterial,layer).lambda;
					
				}
			}
			
			return result;
		}
		
		private static function calculateHomogenLayers(layers:ArrayCollection):Number
		{
			var result:Number = 0;
			
			for each( var layer:Layer in layers)
			{
				if(layer.homogen)
				{
					if(layer.thermalEffect)
					{
						result += (layer.selectedDimention/100) / (layer.materials[0] as Material).lambda;
					}
				}
			}
			
			return result;
		}
		
		private static function getTotalWidthOfMaterialInNothomogenLayers(typeOfMaterial:Number, layers:ArrayCollection):Number
		{
			var result:Number = 0;
			
			for each(var layer:Layer in layers)
			{
				if(!layer.homogen && layerContainsTypeOfMaterial(typeOfMaterial,layer))
				{
					result += getMaterialByType(typeOfMaterial,layer).width/100;
				}
			}
			
			return result;
		}
		
		private static function layerContainsTypeOfMaterial(typeOfMaterial:Number, layer:Layer):Boolean
		{
			var result:Boolean = false;
			
			for each(var material:Material in layer.materials)
			{
				if(material.type == typeOfMaterial)
				{
					result = true;
				}
			}
			
			return result;
		}
		
		private static function getMaterialByType(typeOfMaterial:Number, layer:Layer):Material
		{
			var result:Material = new Material();
			
			for each(var material:Material in layer.materials)
			{
				if(material.type == typeOfMaterial)
				{
					result = material;
				}
			}
			
			return result;
		}
		
		private static function constructionIsHomogen(construction:ConstructionLang):Boolean
		{
			var result:Boolean = true;
			
			for each(var layer:Layer in construction.layers)
			{
				if(!layer.homogen)
				{
					result = false;
				}
			}
			
			return result;
		}
		
		private static function maximumNumberOfMaterialsInSingleLayerInConstruction(construction:ConstructionLang):Number
		{
			var result:Number = 0;
			
			for each(var layer:Layer in construction.layers)
			{
				if(result < layer.materials.length)
				{
					result = layer.materials.length;
				}
			}
			
			return result;
		}
		
		private static function layerHasMaterial(typeOfMaterial:Number, layer:Layer):Boolean
		{
			var result:Boolean = false;
			
			for each(var material:Material in layer.materials)
			{
				if(material.type == typeOfMaterial)
				{
					result = true;
				}
			}
			
			return result;
		}	
		
		private static function getNumberOfHeterogenLayers(construction:ConstructionLang):Number
		{
			var result:Number = 0;
			
			for each(var layer:Layer in construction.layers)
			{
				if(!layer.homogen)
				{
					result++;
				}
			}
			
			return result;
		}
		
		private static function getAllHeterogenLayers(construction:ConstructionLang):ArrayCollection
		{
			var result:ArrayCollection = new ArrayCollection();
			
			for each(var layer:Layer in construction.layers)
			{
				if(!layer.homogen)
				{
					result.addItem(layer);
				}
			}
			
			return result;
		}
	}
}
